// Copyright(c) 2011 Matthew McMullan, Jorel Lalicki and Mike Heise, Jorel Lalicki and Mike Heise. See copying.txt for details.

#ifndef __agml_mbulk_h__
#define __agml_mbulk_h__

// make sure that this file is never included directly
#ifndef __agml_agml_h__
#error "Include AGML from agml.h only. This file is not a valid entry point for the library."
#endif

namespace agml {
	template<typename t, u32 Width, u32 Height> class mrange;
	template<typename t, u32 Width, u32 Height> class mbulk {
	public:
		typedef mstatic<t,Width,Height> mtype;
		typedef mrange<t,Width,Height> mrtype;
		typedef mbulk<t,Width,Height> mbtype;
	protected:
		mtype *data;
		u32 Size, allocated;
	public:
	// constructors
		// init this to an empty container
		mbulk(): data(0), Size(0), allocated(0) {
		}
		// copy constructor
		mbulk(const mbulk &m) {
			Size = m.Size;
			data = (mstatic<t,Width,Height> *)slice_allocator.alloc(Size);
			for (u32 i = 0; i<Size; ++i) {
				data[i] = m.data[i];
			}
		}
	// container stuff
		void reserve(u32 space) {
			if (allocated < space) {
				allocated = slice_allocator.resize(resize,Size,space,space);
			}
		}
		mtype &push_back(const mtype &m) {
			if (allocated<Size++) {
				reserve(Size);
			}
			data[Size-1] = m;
			return data[Size-1];
		}
		void resize(u32 space, mtype filler = mtype()) {
			reserve(space);
			if (Size > space) {
				for (u32 i = Size; i<space; ++i) {
					data[i] = filler;
				}
			}
			Size = space;
		}
	// equality
		bool equals(const mbulk &m, u32 astart, u32 aend, u32 bstart, u32 bend) const {
			bool result = (aend-astart==bend-bstart);
			while (result && astart<aend) {
				result = data[astart] == m.data[bstart];
				astart++; bstart++;
			}
			return result;
		}
		bool operator==(const mbulk &m) const {
			bool result = Size==m.Size;
			u32 i = 0;
			while(result && i<Size) {
				result = data[i]==m.data[i];
				++i;
			}
			return result;
		}
		bool operator!=(const mbulk &m) const {
			bool result = Size!=m.Size;
			u32 i = 0;
			while(!result && i<Size) {
				result = data[i]!=m.data[i];
				++i;
			}
			return result;
		}
	// attributes
		u32 size() const {
			return Size;
		}
	// Indexing
		mrtype extract(u32 start, u32 stop) {
			return mrtype(this, start, stop);
		}
		mrtype vanillaextract(u32 start, u32 stop) {
			return mrtype(this, start, stop);
		}
		mtype &operator[](u32 i) {
			return data[i];
		}
		const mtype &operator[](u32 i) const {
			return data[i];
		}
	// addition
		mbtype &operator+=(const mbtype &m) {
			int s = Size<m.Size?Size:m.size;
			for (u32 i = 0; i < s; ++i) {
				data[i] += m.data[i];
			}
			return *this;
		}
		mbtype &operator+=(const mtype &m) {
			for (u32 i = 0; i < Size; ++i) {
				data[i] += m;
			}
			return *this;
		}
	};
	template<typename t, u32 Width, u32 Height> class mrange {
	public:
		typedef mstatic<t,Width,Height> mtype;
		typedef mrange<t,Width,Height> mrtype;
		typedef mbulk<t,Width,Height> mbtype;
	private:
		mbtype *data;
		u32 start, stop;
	public:
	// constructors
		mrange() {}
		mrange(mbtype *dat, u32 begin, u32 end): data(dat), start(begin), stop(end) {
		}
	// equality
		bool equals(const mbtype &m, u32 begin, u32 end) {
			return data->equals(m, start, stop, begin, end);
		}
		bool operator==(const mbtype &m) const {
			return data->equals(m, start,stop, 0,m.size());
		}
		bool operator==(const mrange &m) const {
			return data->equals(m.data, start,stop, m.start,m.stop);
		}
		bool operator!=(const mbtype &m) const {
			return !data->equals(m, start,stop, 0,m.size());
		}
		bool operator!=(const mrange &m) const {
			return !data->equals(m.data, start,stop, m.start,m.stop);
		}
	// attributes
		bool size() const {
			return stop-start;
		}
	// indexing
		void move(i32 begin, i32 end) {
			start += begin;
			stop += end;
		}
		mtype &operator[](u32 i) {
			return (*data)[i+start];
		}
		const mtype &operator[](u32 i) const {
			return (*data)[i+start];
		}
	};
}

#endif
